package com.ybear.ybutils.utils.design

import androidx.core.util.Consumer
import com.ybear.ybutils.utils.ObjUtils
import com.ybear.ybutils.utils.log.LogUtil

/**
 * 责任链
 */
class ResponsibilityManage {
    companion object {
        private const val TAG = "ResponsibilityManageTAG"
        @JvmStatic
        private val i : ResponsibilityManage by lazy { ResponsibilityManage() }
        @JvmStatic
        fun get(): ResponsibilityManage { return i }
    }

    private val mLoggerMap: MutableMap<Long, AbsLogger> = HashMap()
    private val mEndFinishCall: MutableMap<Long, Consumer<Long>> = HashMap()
    private val mOnLoggerFinishList: MutableList<Consumer<Long>> = ArrayList()

    private fun createId(): Long {
        val newId = ObjUtils.parseLong( Math.random() * Long.MAX_VALUE )
        if( haveLogger( newId ) ) createId()
        return newId
    }

    fun addOnLoggerFinishListener(listener: Consumer<Long>) {
        mOnLoggerFinishList.add( listener )
    }

    fun removeOnLoggerFinishListener(listener: Consumer<Long>) {
        mOnLoggerFinishList.remove( listener )
    }

    fun runLogger(loggerId: Long): Boolean {
        if (!haveLogger(loggerId)) return false
        val logger = mLoggerMap[loggerId] ?: return false
        logger.runLogger()
        return true
    }

    @JvmOverloads
    fun addLogger(
        loggerId: Long = 0L, logger: AbsLogger?,
        finishCall: Consumer<Long>? = null, append: Boolean = true): Long {
        if ( logger == null ) return 0L
        //空id时自动生成新id
        val newId = if( loggerId > 0L )
            loggerId
        else if( logger.loggerId <= 0L ) createId() else logger.loggerId

        //同一个id只追加logger，如果找不到这个id或者追加失败则覆盖当前id
        if( append && haveLogger( newId ) ) {
            if( appendLogger( newId, logger ) ) return newId
        }
        logger.loggerId = newId
        logger.setLoggerEndFinishCall(Consumer { id: Long ->
            for ( call in mOnLoggerFinishList ) {
                call.accept( id )
            }
            try {
                mEndFinishCall[ id ]?.accept( id )
                LogUtil.d( TAG, "addLogger -> addFinishCall -> next loggerId:%s", id )
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                mEndFinishCall.remove( id )
            }
            mLoggerMap.remove( id )
            LogUtil.d( TAG, "addLogger -> addFinishCall -> loggerId:%s", id )
        })
        mLoggerMap[ newId ] = logger
        finishCall?.let { mEndFinishCall[ newId ] = it }
        LogUtil.d( TAG, "addLogger -> loggerId:%s, newId:%s, logger:%s", loggerId, newId, logger )
        return newId
    }

    /**
     * 当前id对应的 [AbsLogger.write] 返回true时，可以调用这个方法触发下一个Logger
     */
    fun nextLogger(loggerId: Long): Boolean {
        if( !haveLogger( loggerId ) ) return false
        val logger = mLoggerMap[ loggerId ] ?: return false
        logger.nextLogger()
        LogUtil.d( TAG, "nextLogger -> loggerId:%s", loggerId )
        return true
    }

    /**
     * 指定id的Logger链路末端处追加新的Logger
     */
    fun appendLogger(appendId: Long, appendLogger: AbsLogger): Boolean {
        if( haveLogger( appendId ) ) {
            appendLogger( mLoggerMap[ appendId ], appendLogger )
            LogUtil.d(
                TAG, "appendLogger suc -> appendId:%s, appendLogger:%s",
                appendId, appendLogger
            )
            return true
        }
        LogUtil.d( TAG, "appendLogger fail -> appendId:%s, appendLogger:%s", appendId, appendLogger )
        return false
    }

    fun haveLogger(loggerId: Long): Boolean {
        return mLoggerMap.containsKey( loggerId )
    }

    private fun appendLogger(logger: AbsLogger?, appendLogger: AbsLogger) {
        if( logger == null ) return
        val next = logger.nextLogger
        if ( next == null ) {
            logger.nextLogger = appendLogger
            return
        }
        appendLogger( next, appendLogger )
    }
}